#include <my_header.h>

//页偏移量
#define PAGE_OFFSET 4096
//一次接收字节大小
#define RECV_SIZE 1024


//客户端下载文件
int client_download(int net_fd)
{

    int flag_client = 0;
    //文件标记位，接收到0表示没有文件可下载，1为有对应文件可以下载
    int recv1 = recv(net_fd, &flag_client, sizeof(flag_client), MSG_WAITALL);
    //printf("after recv\n");
    ERROR_CHECK(recv1, -1, "recv");
    printf("flag_client: %d\n", flag_client);
    if(flag_client == 0){
        printf("没有该文件\n");
        //close(net_fd);
        return 0;
    }

    // 先接收文件完整大小
    off_t file_size = 0;
    //MSG_WAITALL,解决半包问题，接收到指定字节的数据才返回
    recv(net_fd, &file_size, sizeof(off_t), MSG_WAITALL);
    printf("file_size = %ld\n", file_size);

    //文件名长度
    int name_len = 0;
    recv(net_fd, &name_len, sizeof(int), MSG_WAITALL);
    printf("name_len = %d\n", name_len);

    //文件名
    char fileName[60] = {0};
    recv(net_fd, fileName, name_len, MSG_WAITALL);
    printf("name = %s\n", fileName);


    int file_fd = open(fileName, O_RDWR|O_CREAT, 0600);
    ERROR_CHECK(file_fd, -1, "open");
    
    //判断是否有文件，有没有都可以
    struct stat st;
    fstat(file_fd, &st);
    off_t offset = st.st_size;
    

    //给服务器传当前文件的大小
    int offset_send = send(net_fd, &offset, sizeof(off_t), MSG_NOSIGNAL);
    ERROR_CHECK(offset_send, -1, "send");
    
    //计算还有多少没接收的，用于判断
    //这里是完整文件大小与当前文件实际大小的计算
    off_t re_offset = file_size - offset;
    printf("re_offset = %ld\n", re_offset);
    
    //未接收的文件大小<=0
    if(re_offset <= 0){
        printf("已有最新的文件\n");
        close(file_fd);
        return 0;
    }
    
    //计算偏离量,这里截取了当前文件的整数字节大小，为了设置映射偏移量
    //当前文件不满足整4096字节的数据会被ftruncate截断丢弃
    off_t off_reset = offset / PAGE_OFFSET * PAGE_OFFSET;
    printf("off_reset = %ld\n", off_reset);
    
    //调整文件指针移动到文件末尾
    lseek(file_fd, off_reset, SEEK_SET);

    //先设置文件完整大小
    ftruncate(file_fd, file_size);
    
    printf("--download begin--\n");

    //法一，普通接收begin，可用
    //接收字节大小大于等于完整文件大小结束循环
    while(off_reset < file_size){

        //printf("in while\n");
        //先设置文件大小为是偏移量加1024
        ftruncate(file_fd, off_reset + RECV_SIZE);  
        char buf[RECV_SIZE] = {0};

        //printf("in while\n");
        off_t res = recv(net_fd, buf, sizeof(buf), 0);
        ERROR_CHECK(res, -1, "recv");
        //printf("after while recv\n");:wq
        //
        //printf("res: %ld\n", res);
        //printf("res: %d; buf: %s \n", res, buf);

        write(file_fd, buf, res);
        //再设置文件大小为偏移量加实际接收字节
        //文件最后几个字节可能不是1024整数倍，所以再截断保证文件大小与实际匹配
        off_reset = off_reset + res;
        printf("\roff_reset = %ld",off_reset);
        ftruncate(file_fd, off_reset);  
        
        //文件指针移动到文件末尾
        lseek(file_fd, off_reset, SEEK_SET);
        
        //为了截断点设置的睡眠
        usleep(2000);
    }
    //法一，普通接收end
    //
    ////法二，映射接收begin，可用，传太快
    //off_t no_recv_filesize = file_size - off_reset;
    //void *p = mmap(NULL, no_recv_filesize, PROT_READ|PROT_WRITE, MAP_SHARED, file_fd, off_reset);

    //int res_recv = recv(net_fd, p, no_recv_filesize, MSG_WAITALL);
    //ERROR_CHECK(res_recv, -1, "res_recv");

    ////ftruncate(file_fd, file_size);

    //munmap(p, file_size);
    ////法二，映射接收end
    
    printf("下载完成\n");
    close(file_fd);
    return 0;
}

